package com.ikingtech.platform.business.message.controller;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ikingtech.framework.sdk.base.model.PageResult;
import com.ikingtech.framework.sdk.context.exception.FrameworkException;
import com.ikingtech.framework.sdk.context.security.Me;
import com.ikingtech.framework.sdk.core.response.R;
import com.ikingtech.framework.sdk.enums.message.MessageChannelContentTypeEnum;
import com.ikingtech.framework.sdk.enums.message.MessageChannelStatusEnum;
import com.ikingtech.framework.sdk.enums.message.MessageSendChannelEnum;
import com.ikingtech.framework.sdk.message.api.MessageTemplateApi;
import com.ikingtech.framework.sdk.message.model.*;
import com.ikingtech.framework.sdk.message.model.rpc.*;
import com.ikingtech.framework.sdk.utils.Tools;
import com.ikingtech.framework.sdk.web.annotation.ApiController;
import com.ikingtech.framework.sdk.web.annotation.PostRequest;
import com.ikingtech.platform.business.message.entity.*;
import com.ikingtech.platform.business.message.exception.MessageExceptionInfo;
import com.ikingtech.platform.business.message.service.repository.*;
import io.swagger.v3.oas.annotations.Parameter;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * 消息中心-模板管理
 *
 * @author tie yan
 */
@RequiredArgsConstructor
@ApiController(value = "/message/template", name = "消息中心-模板管理", description = "消息中心-模板管理")
public class MessageTemplateController implements MessageTemplateApi {

    private final MessageTemplateRepository repo;

    private final MessageChannelDefinitionRepository channelDefinitionRepo;

    private final MessageParamDefinitionRepository paramDefinitionRepo;

    private final MessageReceiverDefinitionRepository receiverDefinitionRepo;

    private final MessageRedirectDefinitionRepository redirectDefinitionRepo;

    @PostRequest(order = 1, value = "/delete", summary = "删除模板", description = "删除模板")
    public R<Object> delete(@Parameter(name = "id", description = "编号")
                            @RequestBody String id) {
        // 根据编号获取模板实体
        MessageTemplateDO entity = this.repo.getById(id);
        if (null == entity) {
            return R.ok();
        }
        // 如果模板不是可配置的，则抛出异常
        if (!Boolean.TRUE.equals(entity.getConfigurable())) {
            throw new FrameworkException("不允许删除内置模板。");
        }
        // 将模板的配置状态设置为未配置
        entity.setConfigured(false);
        // 更新模板实体
        this.repo.updateById(entity);
        // 根据模板编号删除渠道定义
        this.channelDefinitionRepo.remove(Wrappers.<MessageChannelDefinitionDO>lambdaQuery()
                .eq(MessageChannelDefinitionDO::getTemplateId, id));
        // 根据模板编号删除参数定义
        this.paramDefinitionRepo.remove(Wrappers.<MessageParamDefinitionDO>lambdaQuery()
                .eq(MessageParamDefinitionDO::getTemplateId, id)
                .eq(MessageParamDefinitionDO::getPreDefinition, false));
        // 根据模板编号删除重定向定义
        this.redirectDefinitionRepo.remove(Wrappers.<MessageRedirectDefinitionDO>lambdaQuery()
                .eq(MessageRedirectDefinitionDO::getTemplateId, id));
        return R.ok();
    }

    @PostRequest(order = 2, value = "/update", summary = "更新消息模板", description = "更新消息模板")
    public R<Object> update(@RequestBody MessageTemplateBasicDTO template) {
        // 检查消息模板是否存在
        if (!this.repo.exists(Wrappers.<MessageTemplateDO>lambdaQuery().eq(MessageTemplateDO::getId, template.getId()))) {
            throw new FrameworkException(MessageExceptionInfo.MESSAGE_TEMPLATE_NOT_FOUND);
        }
        // 更新消息模板
        this.repo.updateById(Tools.Bean.copy(template, MessageTemplateDO.class));
        return R.ok();
    }

    @PostRequest(order = 3, value = "/list/page", summary = "分页查询消息模板", description = "分页查询消息模板")
    public R<List<MessageTemplateBasicDTO>> page(@Parameter(name = "queryParam", description = "查询参数")
                                                 @RequestBody MessageTemplateQueryParamDTO queryParam) {
        List<String> templateIds = new ArrayList<>();
        if (Tools.Str.isNotBlank(queryParam.getChannel())) {
            // 根据渠道类型获取消息模板ID列表
            templateIds.addAll(this.channelDefinitionRepo.listObjs(Wrappers.<MessageChannelDefinitionDO>lambdaQuery().select(MessageChannelDefinitionDO::getTemplateId).eq(MessageChannelDefinitionDO::getChannel, queryParam.getChannel())));
            if (Tools.Coll.isBlank(templateIds)) {
                return R.ok(new ArrayList<>());
            }
        }
        // 分页查询消息模板列表，并转换为消息模板基本信息DTO列表
        return R.ok(PageResult.build(this.repo.page(new Page<>(queryParam.getPage(), queryParam.getRows()), Wrappers.<MessageTemplateDO>lambdaQuery()
                .eq(MessageTemplateDO::getConfigured, true)
                .like(Tools.Str.isNotBlank(queryParam.getBusinessKey()), MessageTemplateDO::getBusinessKey, queryParam.getBusinessKey())
                .like(Tools.Str.isNotBlank(queryParam.getBusinessName()), MessageTemplateDO::getBusinessName, queryParam.getBusinessName())
                .like(Tools.Str.isNotBlank(queryParam.getMessageTemplateKey()), MessageTemplateDO::getMessageTemplateKey, queryParam.getMessageTemplateKey())
                .like(Tools.Str.isNotBlank(queryParam.getMessageTemplateTitle()), MessageTemplateDO::getMessageTemplateTitle, queryParam.getMessageTemplateTitle())
                .in(Tools.Coll.isNotBlank(templateIds), MessageTemplateDO::getId, templateIds))).convertBatch(this::modelConvert));
    }

    @PostRequest(order = 4, value = "/info/list/all", summary = "获取所有消息模板", description = "获取所有消息模板")
    public R<List<MessageTemplateBasicDTO>> all() {
        // 调用服务层获取所有消息模板
        return R.ok(this.modelConvert(this.repo.list()));
    }

    @PostRequest(order = 5, value = "/detail/id", summary = "根据id查询消息模板详情", description = "根据id查询消息模板详情")
    public R<MessageTemplateDTO> detail(@RequestBody String id) {
        MessageTemplateDO entity = this.repo.getById(id);
        if (null == entity) {
            throw new FrameworkException(MessageExceptionInfo.MESSAGE_TEMPLATE_NOT_FOUND);
        }
        MessageTemplateDTO result = Tools.Bean.copy(entity, MessageTemplateDTO.class);
        List<MessageChannelDefinitionDO> channelDefinitionEntities = this.channelDefinitionRepo.list(Wrappers.<MessageChannelDefinitionDO>lambdaQuery().eq(MessageChannelDefinitionDO::getTemplateId, id));
        List<MessageChannelDefinitionDTO> channelDefinitions;
        if (Tools.Coll.isNotBlank(channelDefinitionEntities)) {
            List<String> channelDefinitionIds = Tools.Coll.convertList(channelDefinitionEntities, MessageChannelDefinitionDO::getId);
            List<MessageParamDefinitionDO> paramDefinitionEntities = this.paramDefinitionRepo.list(Wrappers.<MessageParamDefinitionDO>lambdaQuery()
                    .in(MessageParamDefinitionDO::getChannelDefinitionId, channelDefinitionIds)
                    .orderByAsc(MessageParamDefinitionDO::getSortOrder));
            Map<String, List<MessageParamDefinitionDO>> paramDefinitionMap = Tools.Coll.convertGroup(paramDefinitionEntities, MessageParamDefinitionDO::getChannelDefinitionId);
            List<MessageRedirectDefinitionDO> redirectDefinitionEntities = this.redirectDefinitionRepo.list(Wrappers.<MessageRedirectDefinitionDO>lambdaQuery().in(MessageRedirectDefinitionDO::getChannelDefinitionId, channelDefinitionIds));
            Map<String, List<MessageRedirectDefinitionDO>> redirectDefinitionMap = Tools.Coll.convertGroup(redirectDefinitionEntities, MessageRedirectDefinitionDO::getChannelDefinitionId);
            channelDefinitions = Tools.Coll.convertList(channelDefinitionEntities, channelDefinitionEntity -> {
                MessageChannelDefinitionDTO channelDefinition = Tools.Bean.copy(channelDefinitionEntity, MessageChannelDefinitionDTO.class);
                channelDefinition.setConfigured(true);
                if (null != channelDefinition.getChannel()) {
                    channelDefinition.setChannelName(channelDefinition.getChannel().description);
                }
                channelDefinition.setStatusName(channelDefinition.getStatus().description);
                channelDefinition.setParamDefinitions(Tools.Coll.convertList(paramDefinitionMap.get(channelDefinitionEntity.getId()), paramDefinitionEntity -> Tools.Bean.copy(paramDefinitionEntity, MessageParamDefinitionDTO.class)));
                channelDefinition.setRedirectDefinitions(Tools.Coll.convertList(redirectDefinitionMap.get(channelDefinitionEntity.getId()), redirectDefinitionEntity -> Tools.Bean.copy(redirectDefinitionEntity, MessageRedirectDefinitionDTO.class)));
                return channelDefinition;
            });
            channelDefinitions.addAll(this.previewChannelDefinition(id, Tools.Coll.convertList(channelDefinitionEntities, channelDefinitionEntity -> MessageSendChannelEnum.valueOf(channelDefinitionEntity.getChannel()))));
        } else {
            channelDefinitions = this.previewChannelDefinition(id);
        }
        result.setChannelDefinitions(channelDefinitions);
        return R.ok(result);
    }

    @PostRequest(order = 6, value = "/business-type/list", summary = "获取业务类型列表", description = "获取业务类型列表")
    public R<List<MessageBusinessTypeDTO>> listBusinessType(@RequestBody MessageBusinessTypeQueryParamDTO queryParam) {
        // 获取业务类型和业务名称列表
        List<MessageTemplateDO> entities = this.repo.list(Wrappers.<MessageTemplateDO>lambdaQuery()
                .like(Tools.Str.isNotBlank(queryParam.getBusinessName()), MessageTemplateDO::getBusinessName, queryParam.getBusinessName())
                .eq(Boolean.TRUE.equals(queryParam.getExcludeAllTemplateConfigured()), MessageTemplateDO::getConfigured, false)
                .eq(Boolean.TRUE.equals(queryParam.getExcludeNonTemplateConfigured()), MessageTemplateDO::getConfigured, true));
        List<MessageBusinessTypeDTO> result = new ArrayList<>();
        entities.forEach(entity -> {
            if (!Tools.Coll.contains(result, MessageBusinessTypeDTO::getBusinessKey, entity.getBusinessKey())) {
                MessageBusinessTypeDTO businessType = new MessageBusinessTypeDTO();
                businessType.setBusinessKey(entity.getBusinessKey());
                businessType.setBusinessName(entity.getBusinessName());
                result.add(businessType);
            }
        });
        return R.ok(result);
    }

    @PostRequest(order = 7, value = "/info/list/business-key", summary = "根据业务标识查询消息模板", description = "根据业务标识查询消息模板")
    public R<List<MessageTemplateBasicDTO>> listInfoByBusinessKey(@Parameter(name = "businessKey", description = "业务标识")
                                                                  @RequestBody String businessKey) {
        // 查询未配置的业务模块消息模板
        List<MessageTemplateDO> entities = this.repo.list(Wrappers.<MessageTemplateDO>lambdaQuery()
                .eq(MessageTemplateDO::getBusinessKey, businessKey)
                .eq(MessageTemplateDO::getConfigured, false));
        // 将查询结果转换为消息模板并返回
        return R.ok(Tools.Coll.convertList(entities, entity -> Tools.Bean.copy(entity, MessageTemplateBasicDTO.class)));
    }

    @Transactional(rollbackFor = Exception.class)
    @PostRequest(order = 8, value = "/channel/definition/add", summary = "添加消息渠道配置信息", description = "添加消息渠道配置信息")
    public R<String> addChannelDefinition(@Parameter(name = "channelDefinition", description = "消息渠道配置信息")
                                          @RequestBody MessageChannelDefinitionDTO channelDefinition) {
        if (this.channelDefinitionRepo.exists(Wrappers.<MessageChannelDefinitionDO>lambdaQuery().eq(MessageChannelDefinitionDO::getTemplateId, channelDefinition.getTemplateId()).eq(MessageChannelDefinitionDO::getChannel, channelDefinition.getChannel().name()))) {
            throw new FrameworkException(MessageExceptionInfo.MESSAGE_CHANNEL_ALREADY_DEFINED);
        }
        MessageTemplateDO templateEntity = this.repo.getOne(Wrappers.<MessageTemplateDO>lambdaQuery()
                .eq(MessageTemplateDO::getId, channelDefinition.getTemplateId())
                .eq(MessageTemplateDO::getTenantCode, Me.tenantCode()));
        templateEntity.setConfigured(true);

        MessageChannelDefinitionDO channelDefinitionEntity = Tools.Bean.copy(channelDefinition, MessageChannelDefinitionDO.class);
        channelDefinitionEntity.setId(Tools.Id.uuid());
        channelDefinitionEntity.setTemplateId(templateEntity.getId());
        channelDefinitionEntity.setTenantCode(Me.tenantCode());
        channelDefinitionEntity.setShowNotification(true);

        this.saveParamAndRedirectDefinition(templateEntity.getId(), channelDefinitionEntity.getId(), channelDefinition);
        this.channelDefinitionRepo.save(channelDefinitionEntity);
        this.repo.updateById(templateEntity);
        return R.ok(channelDefinitionEntity.getId());
    }

    @PostRequest(order = 9, value = "/channel/definition/update", summary = "更新消息渠道配置信息", description = "更新消息渠道配置信息")
    public R<Object> updateChannelDefinition(@Parameter(name = "channelDefinition", description = "消息渠道配置信息")
                                             @RequestBody MessageChannelDefinitionDTO channelDefinition) {
        // 检查消息渠道配置是否存在
        if (!this.channelDefinitionRepo.exists(Wrappers.<MessageChannelDefinitionDO>lambdaQuery().eq(MessageChannelDefinitionDO::getId, channelDefinition.getId()))) {
            throw new FrameworkException(MessageExceptionInfo.MESSAGE_CHANNEL_DEFINITION_NOT_FOUND);
        }
        // 将DTO转换为DO对象
        MessageChannelDefinitionDO entity = Tools.Bean.copy(channelDefinition, MessageChannelDefinitionDO.class);
        // 删除关联的参数定义和重定向定义
        this.paramDefinitionRepo.remove(Wrappers.<MessageParamDefinitionDO>lambdaQuery().eq(MessageParamDefinitionDO::getChannelDefinitionId, channelDefinition.getId()));
        this.redirectDefinitionRepo.remove(Wrappers.<MessageRedirectDefinitionDO>lambdaQuery().eq(MessageRedirectDefinitionDO::getChannelDefinitionId, channelDefinition.getId()));
        // 保存参数定义和重定向定义
        this.saveParamAndRedirectDefinition(channelDefinition.getTemplateId(), channelDefinition.getId(), channelDefinition);
        // 更新消息渠道配置信息
        this.channelDefinitionRepo.updateById(entity);
        return R.ok();
    }

    @PostRequest(order = 10, value = "/channel/definition/enable", summary = "启用消息渠道定义", description = "启用消息渠道定义")
    public R<Object> enableChannelDefinition(@RequestBody String channelDefinitionId) {
        // 获取消息通道定义实体
        MessageChannelDefinitionDO channelDefinitionEntity = this.channelDefinitionRepo.getById(channelDefinitionId);
        // 如果消息通道定义ID为空，则抛出异常
        if (null == channelDefinitionId) {
            throw new FrameworkException(MessageExceptionInfo.MESSAGE_CHANNEL_DEFINITION_NOT_FOUND);
        }
        // 设置消息通道定义状态为启用
        channelDefinitionEntity.setStatus(MessageChannelStatusEnum.ENABLED.name());
        // 更新消息通道定义实体
        this.channelDefinitionRepo.updateById(channelDefinitionEntity);
        // 返回操作结果
        return R.ok();
    }

    @PostRequest(order = 11, value = "/channel/definition/disable", summary = "禁用消息渠道定义", description = "禁用消息渠道定义")
    public R<Object> disableChannelDefinition(@RequestBody String channelDefinitionId) {
        // 根据消息通道定义ID获取消息通道定义实体
        MessageChannelDefinitionDO channelDefinitionEntity = this.channelDefinitionRepo.getById(channelDefinitionId);
        // 如果消息通道定义ID为空，则抛出异常
        if (null == channelDefinitionId) {
            throw new FrameworkException(MessageExceptionInfo.MESSAGE_CHANNEL_DEFINITION_NOT_FOUND);
        }
        // 设置消息通道定义状态为禁用
        channelDefinitionEntity.setStatus(MessageChannelStatusEnum.DISABLED.name());
        // 更新消息通道定义实体
        this.channelDefinitionRepo.updateById(channelDefinitionEntity);
        // 返回成功状态码
        return R.ok();
    }

    @PostRequest(order = 12, value = "/channel/definition/preview/template-id", summary = "根据模板ID预览消息渠道定义", description = "根据模板ID预览消息渠道定义")
    public R<List<MessageChannelDefinitionDTO>> previewChannelDefinitionByTemplateId(@Parameter(name = "templateId", description = "编号")
                                                                                     @RequestBody String templateId) {
        return R.ok(this.previewChannelDefinition(templateId));
    }

    private List<MessageChannelDefinitionDTO> previewChannelDefinition(String templateId) {
        return this.previewChannelDefinition(templateId, new ArrayList<>());
    }

    private List<MessageChannelDefinitionDTO> previewChannelDefinition(String templateId, List<MessageSendChannelEnum> configuredChannel) {
        // 获取未配置的渠道
        List<MessageSendChannelEnum> nonConfiguredChannel = Tools.Array.filter(MessageSendChannelEnum.values(), sendChannel -> !configuredChannel.contains(sendChannel));
        if (Tools.Coll.isBlank(nonConfiguredChannel)) {
            return new ArrayList<>();
        }
        // 获取参数定义实体列表
        List<MessageParamDefinitionDO> paramDefinitionEntities = this.paramDefinitionRepo.list(Wrappers.<MessageParamDefinitionDO>lambdaQuery()
                .eq(MessageParamDefinitionDO::getTemplateId, templateId)
                .eq(MessageParamDefinitionDO::getPreDefinition, true)
                .orderByAsc(MessageParamDefinitionDO::getSortOrder));
        return Tools.Coll.convertList(nonConfiguredChannel, channel -> {
            // 创建渠道定义DTO
            MessageChannelDefinitionDTO channelDefinition = new MessageChannelDefinitionDTO();
            channelDefinition.setChannel(channel);
            channelDefinition.setChannelName(channel.description);
            channelDefinition.setStatus(MessageChannelStatusEnum.DISABLED);
            channelDefinition.setStatusName(MessageChannelStatusEnum.DISABLED.description);
            channelDefinition.setConfigured(false);
            channelDefinition.setParamDefinitions(Tools.Coll.convertList(paramDefinitionEntities, entity -> Tools.Bean.copy(entity, MessageParamDefinitionDTO.class)));
            return channelDefinition;
        });
    }

    @PostRequest(order = 13, value = "/param/pre-definition/id", summary = "获取参数定义列表", description = "获取参数定义列表")
    public R<List<MessageParamDefinitionDTO>> listPreParamDefinitionById(@Parameter(name = "id", description = "编号")
                                                                         @RequestBody String id) {
        List<MessageParamDefinitionDO> entities = this.paramDefinitionRepo.list(Wrappers.<MessageParamDefinitionDO>lambdaQuery()
                .eq(MessageParamDefinitionDO::getTemplateId, id)
                .eq(MessageParamDefinitionDO::getPreDefinition, true)
                .orderByAsc(MessageParamDefinitionDO::getSortOrder));
        return R.ok(Tools.Coll.convertList(entities, entity -> Tools.Bean.copy(entity, MessageParamDefinitionDTO.class)));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R<Object> register(@RequestBody MessageTemplateBeanDefinitionReportParam reportParam) {
        List<MessageTemplateDO> existTemplateEntities = this.repo.list(Wrappers.<MessageTemplateDO>lambdaQuery()
                .in(MessageTemplateDO::getMessageTemplateKey, Tools.Coll.convertList(reportParam.getBeanDefinitions(), MessageTemplateBeanDefinition::getMessageTemplateKey)));
        Map<String, MessageTemplateDO> existTemplateMap = Tools.Coll.convertMap(existTemplateEntities, MessageTemplateDO::getMessageTemplateKey);
        List<String> existTemplateIds = Tools.Coll.convertList(existTemplateEntities, MessageTemplateDO::getId);
        List<MessageChannelDefinitionDO> existChannelDefinitionEntities = Tools.Coll.isBlank(existTemplateIds) ?
                Collections.emptyList() :
                this.channelDefinitionRepo.list(Wrappers.<MessageChannelDefinitionDO>lambdaQuery()
                        .in(MessageChannelDefinitionDO::getTemplateId, existTemplateIds));
        Map<String, List<MessageChannelDefinitionDO>> existChannelDefinitionMap = Tools.Coll.convertGroup(existChannelDefinitionEntities, MessageChannelDefinitionDO::getTemplateId);
        List<MessageRedirectDefinitionDO> existRedirectDefinitionEntities = Tools.Coll.isBlank(existTemplateIds) ?
                Collections.emptyList() :
                this.redirectDefinitionRepo.list(Wrappers.<MessageRedirectDefinitionDO>lambdaQuery()
                        .in(MessageRedirectDefinitionDO::getTemplateId, existTemplateIds));
        Map<String, List<MessageRedirectDefinitionDO>> existRedirectDefinitionMap = Tools.Coll.convertGroup(existRedirectDefinitionEntities, MessageRedirectDefinitionDO::getChannelDefinitionId);
        List<MessageParamDefinitionDO> existParamDefinitionEntities = Tools.Coll.isBlank(existTemplateIds) ?
                Collections.emptyList() :
                this.paramDefinitionRepo.list(Wrappers.<MessageParamDefinitionDO>lambdaQuery()
                        .in(MessageParamDefinitionDO::getTemplateId, existTemplateIds));
        Map<String, List<MessageParamDefinitionDO>> existParamDefinitionMap = Tools.Coll.convertGroup(existParamDefinitionEntities, MessageParamDefinitionDO::getTemplateId);
        List<MessageReceiverDefinitionDO> existReceiverDefinitionEntities = Tools.Coll.isBlank(existTemplateIds) ?
                Collections.emptyList() :
                this.receiverDefinitionRepo.list(Wrappers.<MessageReceiverDefinitionDO>lambdaQuery()
                        .in(MessageReceiverDefinitionDO::getTemplateId, existTemplateIds));
        Map<String, List<MessageReceiverDefinitionDO>> existReceiverDefinitionMap = Tools.Coll.convertGroup(existReceiverDefinitionEntities, MessageReceiverDefinitionDO::getTemplateId);

        List<MessageTemplateDO> templateEntities = new ArrayList<>();
        List<String> deleteTemplateIds = new ArrayList<>();
        List<MessageChannelDefinitionDO> channelDefinitionEntities = new ArrayList<>();
        List<String> deleteChannelDefinitionIds = new ArrayList<>();
        List<MessageParamDefinitionDO> paramDefinitionEntities = new ArrayList<>();
        List<String> deleteParamDefinitionIds = new ArrayList<>();
        List<MessageReceiverDefinitionDO> receiverDefinitionEntities = new ArrayList<>();
        List<String> deleteReceiverDefinitionIds = new ArrayList<>();
        List<MessageRedirectDefinitionDO> redirectDefinitionEntities = new ArrayList<>();
        List<String> deleteRedirectDefinitionIds = new ArrayList<>();
        reportParam.getBeanDefinitions().forEach(beanDefinition -> {
            MessageTemplateDO templateEntity;
            if (!existTemplateMap.containsKey(beanDefinition.getMessageTemplateKey())) {
                templateEntity = Tools.Bean.copy(beanDefinition, MessageTemplateDO.class);
                templateEntity.setId(Tools.Id.uuid());
                templateEntity.setConfigured(beanDefinition.getInternal());
                templateEntity.setConfigurable(true);
                templateEntities.add(templateEntity);
            } else {
                templateEntity = existTemplateMap.get(beanDefinition.getMessageTemplateKey());
            }

            List<MessageParamDefinitionDO> currentTemplateExistParamDefinitionEntities = existParamDefinitionMap.get(templateEntity.getId());
            Map<String, MessageParamDefinitionDO> currentTemplateExistPreDefineParamDefinitionMap = Tools.Coll.convertMap(
                    Tools.Coll.filter(currentTemplateExistParamDefinitionEntities,
                            entity -> Boolean.TRUE.equals(entity.getPreDefinition())),
                    MessageParamDefinitionDO::getParamName
            );
            beanDefinition.getParamDefinitions().forEach(paramDefinition -> {
                if (!currentTemplateExistPreDefineParamDefinitionMap.containsKey(paramDefinition.getParamName())) {
                    paramDefinitionEntities.add(
                            this.createParamDefinition(paramDefinition,
                                    templateEntity.getId(),
                                    Tools.Str.EMPTY,
                                    true)
                    );
                }
                currentTemplateExistPreDefineParamDefinitionMap.remove(paramDefinition.getParamName());
            });
            if (Tools.Coll.isNotBlankMap(currentTemplateExistPreDefineParamDefinitionMap)) {
                deleteParamDefinitionIds.addAll(Tools.Coll.convertList(currentTemplateExistPreDefineParamDefinitionMap.values(),
                        MessageParamDefinitionDO::getId));
            }

            List<MessageReceiverDefinitionDO> currentTemplateExistReceiverDefinitionEntities = existReceiverDefinitionMap.get(templateEntity.getId());
            Map<String, MessageReceiverDefinitionDO> currentTemplateExistReceiverDefinitionMap = Tools.Coll.convertMap(currentTemplateExistReceiverDefinitionEntities,
                    MessageReceiverDefinitionDO::getReceiverParamName);
            beanDefinition.getReceiverDefinitions().forEach(receiverDefinition -> {
                if (!currentTemplateExistReceiverDefinitionMap.containsKey(receiverDefinition.getReceiverParamName())) {
                    MessageReceiverDefinitionDO entity = Tools.Bean.copy(receiverDefinition, MessageReceiverDefinitionDO.class);
                    entity.setId(Tools.Id.uuid());
                    entity.setTemplateId(templateEntity.getId());
                    receiverDefinitionEntities.add(entity);
                }
                currentTemplateExistReceiverDefinitionMap.remove(receiverDefinition.getReceiverParamName());
            });
            if (Tools.Coll.isNotBlankMap(currentTemplateExistReceiverDefinitionMap)) {
                deleteReceiverDefinitionIds.addAll(Tools.Coll.convertList(currentTemplateExistReceiverDefinitionMap.values(), MessageReceiverDefinitionDO::getId));
            }

            Map<String, List<MessageParamDefinitionDO>> currentTemplateExistChannelParamDefinitionMap = Tools.Coll.convertGroup(Tools.Coll.filter(currentTemplateExistParamDefinitionEntities, entity -> !Boolean.TRUE.equals(entity.getPreDefinition())), MessageParamDefinitionDO::getChannelDefinitionId);
            List<MessageChannelDefinitionDO> currentTemplateExistChannelDefinitionEntities = existChannelDefinitionMap.get(templateEntity.getId());
            Map<String, MessageChannelDefinitionDO> currentTemplateExistChannelDefinitionMap = Tools.Coll.convertMap(currentTemplateExistChannelDefinitionEntities, MessageChannelDefinitionDO::getChannel);

            if (Boolean.TRUE.equals(beanDefinition.getInternal()) &&
                Tools.Coll.isNotBlank(beanDefinition.getChannelDefinitions())) {
                beanDefinition.getChannelDefinitions().forEach(channelDefinition -> {
                    if (!currentTemplateExistChannelDefinitionMap.containsKey(channelDefinition.getChannel().name())) {
                        MessageChannelDefinitionDO channelDefinitionEntity = this.createChannelDefinition(templateEntity, channelDefinition);
                        channelDefinitionEntities.add(channelDefinitionEntity);
                        if (Tools.Coll.isNotBlank(channelDefinition.getRedirectDefinitions())) {
                            redirectDefinitionEntities.addAll(Tools.Coll.convertList(channelDefinition.getRedirectDefinitions(), redirectDefinition -> {
                                MessageRedirectDefinitionDO redirectDefinitionEntity = Tools.Bean.copy(redirectDefinition, MessageRedirectDefinitionDO.class);
                                redirectDefinitionEntity.setId(Tools.Id.uuid());
                                redirectDefinitionEntity.setTemplateId(templateEntity.getId());
                                redirectDefinitionEntity.setChannelDefinitionId(channelDefinitionEntity.getId());
                                return redirectDefinitionEntity;
                            }));
                        }
                        if (Tools.Coll.isNotBlank(beanDefinition.getParamDefinitions())) {
                            paramDefinitionEntities.addAll(Tools.Coll.convertList(beanDefinition.getParamDefinitions(), paramDefinition ->
                                    this.createParamDefinition(paramDefinition,
                                            templateEntity.getId(),
                                            channelDefinitionEntity.getId(),
                                            false)
                            ));
                        }
                    } else {
                        MessageChannelDefinitionDO channelDefinitionEntity = currentTemplateExistChannelDefinitionMap.get(channelDefinition.getChannel().name());
                        List<MessageRedirectDefinitionDO> currentChannelRedirectDefinitionEntities = existRedirectDefinitionMap.get(channelDefinitionEntity.getId());
                        Map<String, MessageRedirectDefinitionDO> currentChannelRedirectDefinitionMap = Tools.Coll.convertMap(currentChannelRedirectDefinitionEntities, MessageRedirectDefinitionDO::getRedirectCode);
                        if (Tools.Coll.isNotBlank(channelDefinition.getRedirectDefinitions())) {
                            channelDefinition.getRedirectDefinitions().forEach(redirectDefinition -> {
                                if (!currentChannelRedirectDefinitionMap.containsKey(redirectDefinition.getRedirectCode())) {
                                    MessageRedirectDefinitionDO redirectDefinitionEntity = Tools.Bean.copy(redirectDefinition, MessageRedirectDefinitionDO.class);
                                    redirectDefinitionEntity.setId(Tools.Id.uuid());
                                    redirectDefinitionEntity.setTemplateId(templateEntity.getId());
                                    redirectDefinitionEntity.setChannelDefinitionId(channelDefinitionEntity.getId());
                                    redirectDefinitionEntities.add(redirectDefinitionEntity);
                                }
                                currentChannelRedirectDefinitionMap.remove(redirectDefinition.getRedirectCode());
                            });
                            if (Tools.Coll.isNotBlankMap(currentChannelRedirectDefinitionMap)) {
                                deleteRedirectDefinitionIds.addAll(Tools.Coll.convertList(currentChannelRedirectDefinitionMap.values(), MessageRedirectDefinitionDO::getId));
                            }
                        }
                        if (Tools.Coll.isNotBlank(beanDefinition.getParamDefinitions())) {
                            List<MessageParamDefinitionDO> currentChannelParamDefinitionEntities = currentTemplateExistChannelParamDefinitionMap.get(channelDefinitionEntity.getId());
                            Map<String, MessageParamDefinitionDO> currentChannelParamDefinitionMap = Tools.Coll.convertMap(currentChannelParamDefinitionEntities, MessageParamDefinitionDO::getParamName);
                            beanDefinition.getParamDefinitions().forEach(paramDefinition -> currentChannelParamDefinitionMap.remove(paramDefinition.getParamName()));
                            if (Tools.Coll.isNotBlankMap(currentChannelParamDefinitionMap)) {
                                deleteParamDefinitionIds.addAll(Tools.Coll.convertList(currentChannelParamDefinitionMap.values(), MessageParamDefinitionDO::getId));
                            }
                        }
                    }
                    currentTemplateExistChannelDefinitionMap.remove(channelDefinition.getChannel().name());
                });
                if (Tools.Coll.isNotBlankMap(currentTemplateExistChannelDefinitionMap)) {
                    deleteChannelDefinitionIds.addAll(Tools.Coll.convertList(currentTemplateExistChannelDefinitionMap.values(), MessageChannelDefinitionDO::getId));
                }
            }
            existTemplateMap.remove(beanDefinition.getMessageTemplateKey());
        });
        if (Tools.Coll.isNotBlank(deleteTemplateIds)) {
            deleteTemplateIds.addAll(Tools.Coll.convertList(existTemplateMap.values(), MessageTemplateDO::getId));
        }
        if (Tools.Coll.isNotBlank(templateEntities)) {
            this.repo.saveBatch(templateEntities);
        }
        if (Tools.Coll.isNotBlank(deleteTemplateIds)) {
            this.repo.removeBatchByIds(deleteTemplateIds);
        }
        if (Tools.Coll.isNotBlank(deleteTemplateIds)) {
            this.repo.removeBatchByIds(deleteTemplateIds);
            this.channelDefinitionRepo.remove(Wrappers.<MessageChannelDefinitionDO>lambdaQuery().in(MessageChannelDefinitionDO::getTemplateId, deleteTemplateIds));
            this.paramDefinitionRepo.remove(Wrappers.<MessageParamDefinitionDO>lambdaQuery().in(MessageParamDefinitionDO::getTemplateId, deleteTemplateIds));
            this.receiverDefinitionRepo.remove(Wrappers.<MessageReceiverDefinitionDO>lambdaQuery().in(MessageReceiverDefinitionDO::getTemplateId, deleteTemplateIds));
            this.redirectDefinitionRepo.remove(Wrappers.<MessageRedirectDefinitionDO>lambdaQuery().in(MessageRedirectDefinitionDO::getTemplateId, deleteTemplateIds));
        }

        if (Tools.Coll.isNotBlank(channelDefinitionEntities)) {
            this.channelDefinitionRepo.saveBatch(channelDefinitionEntities);
        }
        if (Tools.Coll.isNotBlank(deleteChannelDefinitionIds)) {
            this.channelDefinitionRepo.removeBatchByIds(deleteChannelDefinitionIds);
        }

        if (Tools.Coll.isNotBlank(paramDefinitionEntities)) {
            this.paramDefinitionRepo.saveBatch(paramDefinitionEntities);
        }
        if (Tools.Coll.isNotBlank(deleteParamDefinitionIds)) {
            this.paramDefinitionRepo.removeBatchByIds(deleteParamDefinitionIds);
        }

        if (Tools.Coll.isNotBlank(receiverDefinitionEntities)) {
            this.receiverDefinitionRepo.saveBatch(receiverDefinitionEntities);
        }
        if (Tools.Coll.isNotBlank(deleteReceiverDefinitionIds)) {
            this.receiverDefinitionRepo.removeBatchByIds(deleteReceiverDefinitionIds);
        }

        if (Tools.Coll.isNotBlank(redirectDefinitionEntities)) {
            this.redirectDefinitionRepo.saveBatch(redirectDefinitionEntities);
        }
        if (Tools.Coll.isNotBlank(deleteRedirectDefinitionIds)) {
            this.redirectDefinitionRepo.removeBatchByIds(deleteRedirectDefinitionIds);
        }
        return R.ok();
    }

    private MessageParamDefinitionDO createParamDefinition(MessageParamDefinition paramDefinition,
                                                           String templateId,
                                                           String channelDefinitionId, Boolean preDefinition) {
        MessageParamDefinitionDO entity = Tools.Bean.copy(paramDefinition, MessageParamDefinitionDO.class);
        entity.setId(Tools.Id.uuid());
        entity.setTenantCode(Me.tenantCode());
        entity.setTemplateId(templateId);
        entity.setChannelDefinitionId(channelDefinitionId);
        entity.setPreDefinition(preDefinition);
        return entity;
    }

    private MessageChannelDefinitionDO createChannelDefinition(MessageTemplateDO templateEntity, MessageChannelDefinition channel) {
        MessageChannelDefinitionDO entity = new MessageChannelDefinitionDO();
        entity.setId(Tools.Id.uuid());
        entity.setTemplateId(templateEntity.getId());
        entity.setBusinessKey(templateEntity.getBusinessKey());
        entity.setBusinessName(templateEntity.getBusinessName());
        entity.setMessageTitle(templateEntity.getMessageTemplateTitle());
        entity.setChannel(channel.getChannel().name());
        entity.setChannelId(channel.getChannelId());
        entity.setChannelTemplateId(channel.getChannelTemplateId());
        entity.setChannelDescription(channel.getChannelName());
        entity.setContent(channel.getTemplateContent());
        entity.setContentType(MessageChannelContentTypeEnum.SELF.name());
        entity.setStatus(MessageChannelStatusEnum.ENABLED.name());
        entity.setShowNotification(channel.getShowNotification());
        return entity;
    }

    private MessageTemplateBasicDTO modelConvert(MessageTemplateDO entity, Map<String, List<String>> channelNameMap) {
        MessageTemplateBasicDTO template = Tools.Bean.copy(entity, MessageTemplateBasicDTO.class);
        if (channelNameMap.containsKey(entity.getId())) {
            template.setChannelNames(Tools.Coll.join(channelNameMap.get(entity.getId())));
        }
        return template;
    }

    private List<MessageTemplateBasicDTO> modelConvert(List<MessageTemplateDO> entities) {
        List<MessageChannelDefinitionDO> channelDefinitionEntities = this.channelDefinitionRepo.list(Wrappers.<MessageChannelDefinitionDO>lambdaQuery().in(MessageChannelDefinitionDO::getTemplateId, Tools.Coll.convertList(entities, MessageTemplateDO::getId)));
        Map<String, List<String>> channelNameMap = Tools.Coll.convertGroup(channelDefinitionEntities, MessageChannelDefinitionDO::getTemplateId, entity -> MessageSendChannelEnum.valueOf(entity.getChannel()).description);
        return Tools.Coll.convertList(entities, entity -> this.modelConvert(entity, channelNameMap));
    }

    private void saveParamAndRedirectDefinition(String templateId, String channelDefinitionId, MessageChannelDefinitionDTO channelDefinition) {
        if (Tools.Coll.isNotBlank(channelDefinition.getParamDefinitions())) {
            this.paramDefinitionRepo.saveBatch(Tools.Coll.convertList(channelDefinition.getParamDefinitions(), paramDefinition -> {
                MessageParamDefinitionDO entity = Tools.Bean.copy(paramDefinition, MessageParamDefinitionDO.class);
                entity.setId(Tools.Id.uuid());
                entity.setTemplateId(templateId);
                entity.setChannelDefinitionId(channelDefinitionId);
                entity.setPreDefinition(false);
                entity.setTenantCode(Me.tenantCode());
                return entity;
            }));
        }

        if (Tools.Coll.isNotBlank(channelDefinition.getRedirectDefinitions())) {
            this.redirectDefinitionRepo.saveBatch(Tools.Coll.convertList(channelDefinition.getRedirectDefinitions(), redirectDefinition -> {
                MessageRedirectDefinitionDO entity = Tools.Bean.copy(redirectDefinition, MessageRedirectDefinitionDO.class);
                entity.setId(Tools.Id.uuid());
                entity.setTemplateId(templateId);
                entity.setChannelDefinitionId(channelDefinitionId);
                entity.setTenantCode(Me.tenantCode());
                return entity;
            }));
        }
    }
}
